//
// Created by yyancy on 2019/11/26.
//
#include <iostream>
#include <vector>
#include <fstream>

using namespace std;

const int not_a_reading = -7777;
const int not_a_month = -1;

void error(string string1) {
    cerr << string1 << "\n";
    exit(1);
}

struct Day {
    vector<double> hour{vector<double>(24, not_a_reading)};
};

struct Month {
    int month{not_a_month};
    vector<Day> day{32};
};

struct Year {
    int year;
    vector<Month> month{12};
};


struct Reading {
    int day;
    int hour;
    double temperature;
};

void print_year(ofstream &ofs, Year &year);

istream &operator>>(istream &is, Reading &r) {
    char ch1;
    if (is >> ch1 && ch1 != '(') {
        is.unget();
        is.clear(ios::failbit);
        return is;
    }

    char ch2;
    int d, h;
    double t;
    is >> d >> h >> t >> ch2;
    if (!is || ch2 != ')') {
        cerr << "bad reading";
        exit(1);
    }
    r.day = d;
    r.hour = h;
    r.temperature = t;
    return is;
}

int month_to_int(string mm) {
    static vector<string> month_input_table = {
            "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"
    };
    for (int i = 0; i < 12; ++i) {
        if (month_input_table[i] == mm)return i;
    }
    return -1;
}

string int_to_month(int i) {
    static vector<string> month_print_table = {
            "January", "February",
            "March", "April", "May",
            "June", "July", "August",
            "September", "October", "November", "December"
    };
    if (i < 0 || 12 <= i)error("bad month index");
    return month_print_table[i];
}

constexpr int implausible_min = -200;
constexpr int implausible_max = 200;

bool is_valid(Reading &r) {

    if (r.day < 1 || 31 < r.day)return false;
    if (r.hour < 0 || 23 < r.hour) return false;
    return !(r.temperature < implausible_min || r.temperature > implausible_max);
}

void end_of_loop(istream &ist, char term, const string &message) {
    if (ist.fail()) {
        ist.clear();
        char ch;
        if (ist >> ch && ch == term)return;
        cerr << message << endl;
        exit(1);
    }
}

istream &operator>>(istream &is, Month &m) {
    char ch = 0;
    if (is >> ch && ch != '{') {
        is.unget();
        is.clear(ios::failbit);
        return is;
    }

    string month_marker;
    string mm;
    is >> month_marker >> mm;
    if (!is || month_marker != "month") {
        cerr << "bad start of month";
        exit(1);
    }
    m.month = month_to_int(mm);

    int duplicates = 0;
    int invalids = 0;
    for (Reading r; is >> r;) {
        if (is_valid(r)) {
            if (m.day[r.day].hour[r.hour] != not_a_reading) {
                ++duplicates;
            }
            m.day[r.day].hour[r.hour] = r.temperature;
        } else {
            ++invalids;
        }
    }
    if (invalids)error("invalid readings in month");
    if (duplicates)error("duplicate reading in month");
    cout << m.month << endl;
    end_of_loop(is, '}', "bad end of month");
    return is;
}

ostream &operator<<(ostream &os, Day &d) {
    for (int i = 0; i < d.hour.size(); ++i) {
        if (d.hour[i] != not_a_reading) {
            os << d.hour[i] << "C";
            if (i != d.hour.size() - 1) {
                os << ',';
            }
        }
    }
    os << '\r';
}

bool is_valid_day(Day &d) {
    for (int i = 0; i < d.hour.size(); ++i) {
        if (d.hour[i] != not_a_reading)return true;
    }
    return false;
}

ostream &operator<<(ostream &os, Month &m) {
    os << "month " << m.month << endl;

    for (int i = 0; i < m.day.size(); ++i) {
        if (!is_valid_day(m.day[i]))continue;
        os << "\t\t";
        os << "day " << i << ": ";
        os << m.day[i];
    }

}

istream &operator>>(istream &is, Year &y) {
    char ch;
    is >> ch;
    if (ch != '{') {
        is.unget();
        is.clear(ios::failbit);
        return is;
    }

    string year_marker;
    int yy;
    is >> year_marker >> yy;
    if (!is || year_marker != "year")error("bad start of year");
    y.year = yy;

    while (true) {
        Month m;
        if (!(is >> m))break;
        y.month[m.month] = m;
    }
    end_of_loop(is, '}', "bad end of year");
    return is;
}

ostream &operator<<(ostream &os, Year &y) {
    os << "year" << y.year << endl;

    for (int i = 0; i < y.month.size(); ++i) {
        if (y.month[i].month != not_a_month) {
            os << '\t';
            os << y.month[i];
        }

    }
    os << endl;
}

void print_year(ofstream &ofs, Year &year) {
    ofs << year;
}

int main() {
    cout << "Please enter input file name\n";
    string iname = "temperature.txt";
//    cin >> iname;
    ifstream ifs{iname};
    if (!ifs)error("can't open input file" + iname);

    ifs.exceptions(ifs.exceptions() | ios_base::badbit);

    cout << "Please enter output file name\n";
    string oname = "output.txt";
//    cin >> oname;
    ofstream ofs{oname};
    if (!ofs)error("can't open output file" + oname);

    vector<Year> ys;
    while (true) {
        Year y;
        if (!(ifs >> y))break;
        ys.push_back(y);
    }

    cout << "read " << ys.size() << "years of readings\n";

    for (Year &y:ys)print_year(ofs, y);
}


